<?php
/**
 * 个人账户业务逻辑类
 * User: 苏近之
 * Date: 2019-03-23
 * Time: 17:06
 */

namespace app\user\service;

use app\common\enum\LogCategory;
use app\common\enum\LogLevel;
use app\common\service\LogService;
use app\user\enum\CacheKeys;
use app\user\exception\PhoneAgainRegister;
use app\user\exception\RegisterNicknameAlreadyExists;
use app\user\exception\RegisterSubmitTokenError;
use app\user\exception\RegisterVerifyCodeError;
use app\user\exception\UserLoginInfoSaveFailed;
use think\facade\Request;
use think\facade\Cache;

class PersonAccountService
{
    // 注册验证手机号返回 TOKEN 有效时间
    const REGISTER_VERIFY_TOKEN_EXPIRE = 600;

    /**
     * 验证注册手机号以及验证码
     * @param string $phone 手机号
     * @param int|string $verifyCode 验证码
     * @throws PhoneAgainRegister
     * @throws RegisterVerifyCodeError
     * @return string
     */
    public static function verifyPhoneAndCode($phone, $verifyCode): string
    {
        // 检查手机号是否已经被注册
        if (UserInfoService::hasRegisterWithPhone($phone)) {
            throw new PhoneAgainRegister();
        }
        // 检查验证码是否正确
        if (!SmsService::setPhone($phone)->checkVerifyCode($verifyCode)) {
            // 记录日志
            $title = 'Register phone verify code error';
            LogService::write($title, LogCategory::USER_REGISTER, LogLevel::ERROR, [
                'phone' => $phone,
                'verifyCode' => $verifyCode,
            ]);
            throw new RegisterVerifyCodeError();
        }
        // 删除验证码
        SmsService::setPhone($phone)->removeVerifyCode();
        // 保存并返回一个随机数
        $token = hash('sha256', mt_rand(1000, 9999));
        $key = sprintf(CacheKeys::REGISTER_PHONE_VERIFY_RETURN_TOKEN, $phone);
        Cache::set($key, $token, self::REGISTER_VERIFY_TOKEN_EXPIRE);

        return $token;
    }

    /**
     * 提交用户注册信息
     * @param array $registerInfo
     * @throws RegisterSubmitTokenError
     * @throws PhoneAgainRegister
     * @throws RegisterNicknameAlreadyExists
     * @throws UserLoginInfoSaveFailed
     */
    public static function submitRegisterInfo(array $registerInfo)
    {
        // 检查 Token 是否正确
        $key = sprintf(CacheKeys::REGISTER_PHONE_VERIFY_RETURN_TOKEN, $registerInfo['phone']);
        $storeToken = Cache::get($key, '');
        if ($storeToken !== $registerInfo['token']) {
            throw new RegisterSubmitTokenError();
        }
        // 检查手机号是否已经被注册
        if (UserInfoService::hasRegisterWithPhone($registerInfo['phone'])) {
            throw new PhoneAgainRegister();
        }
        // 检查用户名是否已经存在
        if (UserInfoService::hasRegisterWithName($registerInfo['registerName'])) {
            throw new RegisterNicknameAlreadyExists();
        }
        // 保存注册信息
        $result = UserInfoService::saveUserLoginInfo($registerInfo['registerName'], $registerInfo['phone'],
            $registerInfo['password']);
        if (!$result) {
            throw new UserLoginInfoSaveFailed();
        }
        // 删除 Token
        Cache::rm(sprintf(CacheKeys::REGISTER_PHONE_VERIFY_RETURN_TOKEN, $registerInfo['phone']));
        // 记录日志
        LogService::write('User register success', LogCategory::USER_REGISTER, LogLevel::NOTICE, [
            'phone' => $registerInfo['phone'],
            'registerName' => $registerInfo['registerName'],
            'token' => $registerInfo['token'],
            'ip' => Request::ip(),
        ]);
    }

}